home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / text / edit / vim60src.lha / Vim / vim60 / src / memfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-09  |  31.5 KB  |  1,280 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  8.  */
  9.  
  10. /*
  11.  * memfile.c: Contains the functions for handling blocks of memory which can
  12.  * be stored in a file. This is the implementation of a sort of virtual memory.
  13.  *
  14.  * A memfile consists of a sequence of blocks. The blocks numbered from 0
  15.  * upwards have been assigned a place in the actual file. The block number
  16.  * is equal to the page number in the file. The
  17.  * blocks with negative numbers are currently in memory only. They can be
  18.  * assigned a place in the file when too much memory is being used. At that
  19.  * moment they get a new, positive, number. A list is used for translation of
  20.  * negative to positive numbers.
  21.  *
  22.  * The size of a block is a multiple of a page size, normally the page size of
  23.  * the device the file is on. Most blocks are 1 page long. A Block of multiple
  24.  * pages is used for a line that does not fit in a single page.
  25.  *
  26.  * Each block can be in memory and/or in a file. The block stays in memory
  27.  * as long as it is locked. If it is no longer locked it can be swapped out to
  28.  * the file. It is only written to the file if it has been changed.
  29.  *
  30.  * Under normal operation the file is created when opening the memory file and
  31.  * deleted when closing the memory file. Only with recovery an existing memory
  32.  * file is opened.
  33.  */
  34.  
  35. #if defined MSDOS || defined(WIN32) || defined(_WIN64)
  36. # include <io.h>    /* for lseek(), must be before vim.h */
  37. #endif
  38.  
  39. #include "vim.h"
  40.  
  41. #ifdef HAVE_FCNTL_H
  42. # include <fcntl.h>
  43. #endif
  44.  
  45. /*
  46.  * Some systems have the page size in statfs.f_bsize, some in stat.st_blksize
  47.  */
  48. #ifdef HAVE_ST_BLKSIZE
  49. # define STATFS stat
  50. # define F_BSIZE st_blksize
  51. # define fstatfs(fd, buf, len, nul) mch_fstat((fd), (buf))
  52. #else
  53. # ifdef HAVE_SYS_STATFS_H
  54. #  include <sys/statfs.h>
  55. #  define STATFS statfs
  56. #  define F_BSIZE f_bsize
  57. #  ifdef __MINT__        /* do we still need this? */
  58. #   define fstatfs(fd, buf, len, nul) mch_fstat((fd), (buf))
  59. #  endif
  60. # endif
  61. #endif
  62.  
  63. /*
  64.  * for Amiga Dos 2.0x we use Flush
  65.  */
  66. #ifdef AMIGA
  67. # ifdef FEAT_ARP
  68. extern int dos2;            /* this is in os_amiga.c */
  69. # endif
  70. # ifdef SASC
  71. #  include <proto/dos.h>
  72. #  include <ios1.h>            /* for chkufb() */
  73. # endif
  74. #endif
  75.  
  76. #define MEMFILE_PAGE_SIZE 4096        /* default page size */
  77.  
  78. static long_u    total_mem_used = 0;    /* total memory used for memfiles */
  79. static int    dont_release = FALSE;    /* don't release blocks */
  80.  
  81. static void mf_ins_hash __ARGS((memfile_T *, bhdr_T *));
  82. static void mf_rem_hash __ARGS((memfile_T *, bhdr_T *));
  83. static bhdr_T *mf_find_hash __ARGS((memfile_T *, blocknr_T));
  84. static void mf_ins_used __ARGS((memfile_T *, bhdr_T *));
  85. static void mf_rem_used __ARGS((memfile_T *, bhdr_T *));
  86. static bhdr_T *mf_release __ARGS((memfile_T *, int));
  87. static bhdr_T *mf_alloc_bhdr __ARGS((memfile_T *, int));
  88. static void mf_free_bhdr __ARGS((bhdr_T *));
  89. static void mf_ins_free __ARGS((memfile_T *, bhdr_T *));
  90. static bhdr_T *mf_rem_free __ARGS((memfile_T *));
  91. static int  mf_read __ARGS((memfile_T *, bhdr_T *));
  92. static int  mf_write __ARGS((memfile_T *, bhdr_T *));
  93. static int  mf_trans_add __ARGS((memfile_T *, bhdr_T *));
  94. static void mf_do_open __ARGS((memfile_T *, char_u *, int));
  95.  
  96. /*
  97.  * The functions for using a memfile:
  98.  *
  99.  * mf_open()        open a new or existing memfile
  100.  * mf_open_file()   open a swap file for an existing memfile
  101.  * mf_close()        close (and delete) a memfile
  102.  * mf_new()        create a new block in a memfile and lock it
  103.  * mf_get()        get an existing block and lock it
  104.  * mf_put()        unlock a block, may be marked for writing
  105.  * mf_free()        remove a block
  106.  * mf_sync()        sync changed parts of memfile to disk
  107.  * mf_release_all() release as much memory as possible
  108.  * mf_trans_del()   may translate negative to positive block number
  109.  * mf_fullname()    make file name full path (use before first :cd)
  110.  */
  111.  
  112. /*
  113.  * Open an existing or new memory block file.
  114.  *
  115.  *  fname:    name of file to use (NULL means no file at all)
  116.  *        Note: fname must have been allocated, it is not copied!
  117.  *            If opening the file fails, fname is freed.
  118.  *  flags:    flags for open() call
  119.  *
  120.  *  If fname != NULL and file cannot be opened, fail.
  121.  *
  122.  * return value: identifier for this memory block file.
  123.  */
  124.     memfile_T *
  125. mf_open(fname, flags)
  126.     char_u    *fname;
  127.     int        flags;
  128. {
  129.     memfile_T        *mfp;
  130.     int            i;
  131.     off_t        size;
  132. #if defined(STATFS) && defined(UNIX) && !defined(__QNX__)
  133. # define USE_FSTATFS
  134.     struct STATFS    stf;
  135. #endif
  136.  
  137.     if ((mfp = (memfile_T *)alloc((unsigned)sizeof(memfile_T))) == NULL)
  138.     return NULL;
  139.  
  140.     if (fname == NULL)        /* no file for this memfile, use memory only */
  141.     {
  142.     mfp->mf_fname = NULL;
  143.     mfp->mf_ffname = NULL;
  144.     mfp->mf_fd = -1;
  145.     }
  146.     else
  147.     {
  148.     mf_do_open(mfp, fname, flags);    /* try to open the file */
  149.  
  150.     /* if the file cannot be opened, return here */
  151.     if (mfp->mf_fd < 0)
  152.     {
  153.         vim_free(mfp);
  154.         return NULL;
  155.     }
  156.     }
  157.  
  158.     mfp->mf_free_first = NULL;        /* free list is empty */
  159.     mfp->mf_used_first = NULL;        /* used list is empty */
  160.     mfp->mf_used_last = NULL;
  161.     mfp->mf_dirty = FALSE;
  162.     mfp->mf_used_count = 0;
  163.     for (i = 0; i < MEMHASHSIZE; ++i)
  164.     {
  165.     mfp->mf_hash[i] = NULL;        /* hash lists are empty */
  166.     mfp->mf_trans[i] = NULL;    /* trans lists are empty */
  167.     }
  168.     mfp->mf_page_size = MEMFILE_PAGE_SIZE;
  169.  
  170. #ifdef USE_FSTATFS
  171.     /*
  172.      * Try to set the page size equal to the block size of the device.
  173.      * Speeds up I/O a lot.
  174.      * When recovering, the actual block size will be retrieved from block 0
  175.      * in ml_recover().  The size used here may be wrong, therefore
  176.      * mf_blocknr_max must be rounded up.
  177.      */
  178.     if (mfp->mf_fd >= 0
  179.         && fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0
  180.         && stf.F_BSIZE >= MIN_SWAP_PAGE_SIZE
  181.         && stf.F_BSIZE <= MAX_SWAP_PAGE_SIZE)
  182.     mfp->mf_page_size = stf.F_BSIZE;
  183. #endif
  184.  
  185.     if (mfp->mf_fd < 0 || (flags & (O_TRUNC|O_EXCL))
  186.               || (size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0)
  187.     mfp->mf_blocknr_max = 0;    /* no file or empty file */
  188.     else
  189.     mfp->mf_blocknr_max = (blocknr_T)((size + mfp->mf_page_size - 1)
  190.                              / mfp->mf_page_size);
  191.     mfp->mf_blocknr_min = -1;
  192.     mfp->mf_neg_count = 0;
  193.     mfp->mf_infile_count = mfp->mf_blocknr_max;
  194.     mfp->mf_used_count_max = p_mm * 1024 / mfp->mf_page_size;
  195.  
  196.     return mfp;
  197. }
  198.  
  199. /*
  200.  * Open a file for an existing memfile.  Used when updatecount set from 0 to
  201.  * some value.
  202.  * If the file already exists, this fails.
  203.  * "fname" is the name of file to use (NULL means no file at all)
  204.  * Note: "fname" must have been allocated, it is not copied!  If opening the
  205.  * file fails, "fname" is freed.
  206.  *
  207.  * return value: FAIL if file could not be opened, OK otherwise
  208.  */
  209.     int
  210. mf_open_file(mfp, fname)
  211.     memfile_T    *mfp;
  212.     char_u    *fname;
  213. {
  214.     mf_do_open(mfp, fname, O_RDWR|O_CREAT|O_EXCL); /* try to open the file */
  215.  
  216.     if (mfp->mf_fd < 0)
  217.     return FAIL;
  218.  
  219.     mfp->mf_dirty = TRUE;
  220.     return OK;
  221. }
  222.  
  223. /*
  224.  * close a memory file and delete the associated file if 'del_file' is TRUE
  225.  */
  226.     void
  227. mf_close(mfp, del_file)
  228.     memfile_T    *mfp;
  229.     int        del_file;
  230. {
  231.     bhdr_T    *hp, *nextp;
  232.     NR_TRANS    *tp, *tpnext;
  233.     int        i;
  234.  
  235.     if (mfp == NULL)            /* safety check */
  236.     return;
  237.     if (mfp->mf_fd >= 0)
  238.     {
  239.     if (close(mfp->mf_fd) < 0)
  240.         EMSG(_(e_swapclose));
  241.     }
  242.     if (del_file && mfp->mf_fname != NULL)
  243.     mch_remove(mfp->mf_fname);
  244.                         /* free entries in used list */
  245.     for (hp = mfp->mf_used_first; hp != NULL; hp = nextp)
  246.     {
  247.     total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
  248.     nextp = hp->bh_next;
  249.     mf_free_bhdr(hp);
  250.     }
  251.     while (mfp->mf_free_first != NULL)        /* free entries in free list */
  252.     vim_free(mf_rem_free(mfp));
  253.     for (i = 0; i < MEMHASHSIZE; ++i)        /* free entries in trans lists */
  254.     for (tp = mfp->mf_trans[i]; tp != NULL; tp = tpnext)
  255.     {
  256.         tpnext = tp->nt_next;
  257.         vim_free(tp);
  258.     }
  259.     vim_free(mfp->mf_fname);
  260.     vim_free(mfp->mf_ffname);
  261.     vim_free(mfp);
  262. }
  263.  
  264. /*
  265.  * Close the swap file for a memfile.  Used when 'swapfile' is reset.
  266.  */
  267.     void
  268. mf_close_file(buf, getlines)
  269.     buf_T    *buf;
  270.     int        getlines;    /* get all lines into memory? */
  271. {
  272.     memfile_T    *mfp;
  273.     linenr_T    lnum;
  274.  
  275.     mfp = buf->b_ml.ml_mfp;
  276.     if (mfp == NULL || mfp->mf_fd < 0)        /* nothing to close */
  277.     return;
  278.  
  279.     if (getlines)
  280.     {
  281.     /* get all blocks in memory by accessing all lines (clumsy!) */
  282.     dont_release = TRUE;
  283.     for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum)
  284.         (void)ml_get_buf(buf, lnum, FALSE);
  285.     dont_release = FALSE;
  286.     /* TODO: should check if all blocks are really in core */
  287.     }
  288.  
  289.     if (close(mfp->mf_fd) < 0)            /* close the file */
  290.     EMSG(_(e_swapclose));
  291.     mfp->mf_fd = -1;
  292.  
  293.     if (mfp->mf_fname != NULL)
  294.     {
  295.     mch_remove(mfp->mf_fname);        /* delete the swap file */
  296.     vim_free(mfp->mf_fname);
  297.     vim_free(mfp->mf_ffname);
  298.     mfp->mf_fname = NULL;
  299.     mfp->mf_ffname = NULL;
  300.     }
  301. }
  302.  
  303. /*
  304.  * get a new block
  305.  *
  306.  *   negative: TRUE if negative block number desired (data block)
  307.  */
  308.     bhdr_T *
  309. mf_new(mfp, negative, page_count)
  310.     memfile_T    *mfp;
  311.     int        negative;
  312.     int        page_count;
  313. {
  314.     bhdr_T    *hp;        /* new bhdr_T */
  315.     bhdr_T    *freep;        /* first block in free list */
  316.     char_u  *p;
  317.  
  318.     /*
  319.      * If we reached the maximum size for the used memory blocks, release one
  320.      * If a bhdr_T is returned, use it and adjust the page_count if necessary.
  321.      */
  322.     hp = mf_release(mfp, page_count);
  323.  
  324. /*
  325.  * Decide on the number to use:
  326.  * If there is a free block, use its number.
  327.  * Otherwise use mf_block_min for a negative number, mf_block_max for
  328.  * a positive number.
  329.  */
  330.     freep = mfp->mf_free_first;
  331.     if (!negative && freep != NULL && freep->bh_page_count >= page_count)
  332.     {
  333.     /*
  334.      * If the block in the free list has more pages, take only the number
  335.      * of pages needed and allocate a new bhdr_T with data
  336.      *
  337.      * If the number of pages matches and mf_release did not return a bhdr_T,
  338.      * use the bhdr_T from the free list and allocate the data
  339.      *
  340.      * If the number of pages matches and mf_release returned a bhdr_T,
  341.      * just use the number and free the bhdr_T from the free list
  342.      */
  343.     if (freep->bh_page_count > page_count)
  344.     {
  345.         if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  346.         return NULL;
  347.         hp->bh_bnum = freep->bh_bnum;
  348.         freep->bh_bnum += page_count;
  349.         freep->bh_page_count -= page_count;
  350.     }
  351.     else if (hp == NULL)        /* need to allocate memory for this block */
  352.     {
  353.         if ((p = (char_u *)alloc(mfp->mf_page_size * page_count)) == NULL)
  354.         return NULL;
  355.         hp = mf_rem_free(mfp);
  356.         hp->bh_data = p;
  357.     }
  358.     else            /* use the number, remove entry from free list */
  359.     {
  360.         freep = mf_rem_free(mfp);
  361.         hp->bh_bnum = freep->bh_bnum;
  362.         vim_free(freep);
  363.     }
  364.     }
  365.     else    /* get a new number */
  366.     {
  367.     if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  368.         return NULL;
  369.     if (negative)
  370.     {
  371.         hp->bh_bnum = mfp->mf_blocknr_min--;
  372.         mfp->mf_neg_count++;
  373.     }
  374.     else
  375.     {
  376.         hp->bh_bnum = mfp->mf_blocknr_max;
  377.         mfp->mf_blocknr_max += page_count;
  378.     }
  379.     }
  380.     hp->bh_flags = BH_LOCKED | BH_DIRTY;    /* new block is always dirty */
  381.     mfp->mf_dirty = TRUE;
  382.     hp->bh_page_count = page_count;
  383.     mf_ins_used(mfp, hp);
  384.     mf_ins_hash(mfp, hp);
  385.  
  386.     /*
  387.      * Init the data to all zero, to avoid reading uninitialized data.
  388.      * This also avoids that the passwd file ends up in the swap file!
  389.      */
  390.     (void)vim_memset((char *)(hp->bh_data), 0, (size_t)mfp->mf_page_size);
  391.  
  392.     return hp;
  393. }
  394.  
  395. /*
  396.  * get existing block 'nr' with 'page_count' pages
  397.  *
  398.  * Note: The caller should first check a negative nr with mf_trans_del()
  399.  */
  400.     bhdr_T *
  401. mf_get(mfp, nr, page_count)
  402.     memfile_T    *mfp;
  403.     blocknr_T    nr;
  404.     int        page_count;
  405. {
  406.     bhdr_T    *hp;
  407.                         /* doesn't exist */
  408.     if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min)
  409.     return NULL;
  410.  
  411.     /*
  412.      * see if it is in the cache
  413.      */
  414.     hp = mf_find_hash(mfp, nr);
  415.     if (hp == NULL)    /* not in the hash list */
  416.     {
  417.     if (nr < 0 || nr >= mfp->mf_infile_count)   /* can't be in the file */
  418.         return NULL;
  419.  
  420.     /* could check here if the block is in the free list */
  421.  
  422.     /*
  423.      * Check if we need to flush an existing block.
  424.      * If so, use that block.
  425.      * If not, allocate a new block.
  426.      */
  427.     hp = mf_release(mfp, page_count);
  428.     if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  429.         return NULL;
  430.  
  431.     hp->bh_bnum = nr;
  432.     hp->bh_flags = 0;
  433.     hp->bh_page_count = page_count;
  434.     if (mf_read(mfp, hp) == FAIL)        /* cannot read the block! */
  435.     {
  436.         mf_free_bhdr(hp);
  437.         return NULL;
  438.     }
  439.     }
  440.     else
  441.     {
  442.     mf_rem_used(mfp, hp);    /* remove from list, insert in front below */
  443.     mf_rem_hash(mfp, hp);
  444.     }
  445.  
  446.     hp->bh_flags |= BH_LOCKED;
  447.     mf_ins_used(mfp, hp);    /* put in front of used list */
  448.     mf_ins_hash(mfp, hp);    /* put in front of hash list */
  449.  
  450.     return hp;
  451. }
  452.  
  453. /*
  454.  * release the block *hp
  455.  *
  456.  *   dirty: Block must be written to file later
  457.  *   infile: Block should be in file (needed for recovery)
  458.  *
  459.  *  no return value, function cannot fail
  460.  */
  461.     void
  462. mf_put(mfp, hp, dirty, infile)
  463.     memfile_T    *mfp;
  464.     bhdr_T    *hp;
  465.     int        dirty;
  466.     int        infile;
  467. {
  468.     int        flags;
  469.  
  470.     flags = hp->bh_flags;
  471.  
  472.     if ((flags & BH_LOCKED) == 0)
  473.     EMSG(_("E293: block was not locked"));
  474.     flags &= ~BH_LOCKED;
  475.     if (dirty)
  476.     {
  477.     flags |= BH_DIRTY;
  478.     mfp->mf_dirty = TRUE;
  479.     }
  480.     hp->bh_flags = flags;
  481.     if (infile)
  482.     mf_trans_add(mfp, hp);        /* may translate negative in positive nr */
  483. }
  484.  
  485. /*
  486.  * block *hp is no longer in used, may put it in the free list of memfile *mfp
  487.  */
  488.     void
  489. mf_free(mfp, hp)
  490.     memfile_T    *mfp;
  491.     bhdr_T    *hp;
  492. {
  493.     vim_free(hp->bh_data);    /* free the memory */
  494.     mf_rem_hash(mfp, hp);    /* get *hp out of the hash list */
  495.     mf_rem_used(mfp, hp);    /* get *hp out of the used list */
  496.     if (hp->bh_bnum < 0)
  497.     {
  498.     vim_free(hp);        /* don't want negative numbers in free list */
  499.     mfp->mf_neg_count--;
  500.     }
  501.     else
  502.     mf_ins_free(mfp, hp);    /* put *hp in the free list */
  503. }
  504.  
  505. /*
  506.  * Sync the memory file *mfp to disk.
  507.  * Flags:
  508.  *  MFS_ALL    If not given, blocks with negative numbers are not synced,
  509.  *        even when they are dirty!
  510.  *  MFS_STOP    Stop syncing when a character becomes available, but sync at
  511.  *        least one block.
  512.  *  MFS_FLUSH    Make sure buffers are flushed to disk, so they will survive a
  513.  *        system crash.
  514.  *  MFS_ZERO    Only write block 0.
  515.  *
  516.  * Return FAIL for failure, OK otherwise
  517.  */
  518.     int
  519. mf_sync(mfp, flags)
  520.     memfile_T    *mfp;
  521.     int        flags;
  522. {
  523.     int        status;
  524.     bhdr_T    *hp;
  525. #if defined(SYNC_DUP_CLOSE) && !defined(MSDOS)
  526.     int        fd;
  527. #endif
  528.     int        got_int_save = got_int;
  529.  
  530.     if (mfp->mf_fd < 0)        /* there is no file, nothing to do */
  531.     {
  532.     mfp->mf_dirty = FALSE;
  533.     return FAIL;
  534.     }
  535.  
  536.     /* Only a CTRL-C while writing will break us here, not one typed
  537.      * previously. */
  538.     got_int = FALSE;
  539.  
  540.     /*
  541.      * sync from last to first (may reduce the probability of an inconsistent
  542.      * file) If a write fails, it is very likely caused by a full filesystem.
  543.      * Then we only try to write blocks within the existing file. If that also
  544.      * fails then we give up.
  545.      */
  546.     status = OK;
  547.     for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
  548.     if (((flags & MFS_ALL) || hp->bh_bnum >= 0)
  549.         && (hp->bh_flags & BH_DIRTY)
  550.         && (status == OK || (hp->bh_bnum >= 0
  551.             && hp->bh_bnum < mfp->mf_infile_count)))
  552.     {
  553.         if ((flags & MFS_ZERO) && hp->bh_bnum != 0)
  554.         continue;
  555.         if (mf_write(mfp, hp) == FAIL)
  556.         {
  557.         if (status == FAIL)    /* double error: quit syncing */
  558.             break;
  559.         status = FAIL;
  560.         }
  561.         if (flags & MFS_STOP)
  562.         {
  563.         /* Stop when char available now. */
  564.         if (ui_char_avail())
  565.             break;
  566.         }
  567.         else
  568.         ui_breakcheck();
  569.         if (got_int)
  570.         break;
  571.     }
  572.  
  573.     /*
  574.      * If the whole list is flushed, the memfile is not dirty anymore.
  575.      * In case of an error this flag is also set, to avoid trying all the time.
  576.      */
  577.     if (hp == NULL || status == FAIL)
  578.     mfp->mf_dirty = FALSE;
  579.  
  580.     if ((flags & MFS_FLUSH) && *p_sws != NUL)
  581.     {
  582. #if defined(UNIX)
  583. # ifdef HAVE_FSYNC
  584.     /*
  585.      * most Unixes have the very useful fsync() function, just what we need.
  586.      * However, with OS/2 and EMX it is also available, but there are
  587.      * reports of bad problems with it (a bug in HPFS.IFS).
  588.      * So we disable use of it here in case someone tries to be smart
  589.      * and changes os_os2_cfg.h... (even though there is no __EMX__ test
  590.      * in the #if, as __EMX__ does not have sync(); we hope for a timely
  591.      * sync from the system itself).
  592.      */
  593. #  if defined(__EMX__)
  594.    error "Dont use fsync with EMX! Read emxdoc.doc or emxfix01.doc for info."
  595. #  endif
  596.     if (STRCMP(p_sws, "fsync") == 0)
  597.     {
  598.         if (fsync(mfp->mf_fd))
  599.         status = FAIL;
  600.     }
  601.     else
  602. # endif
  603. # ifdef __OPENNT
  604.         fflush(NULL);    /* OpenNT is strictly POSIX (Benzinger) */
  605. # else
  606.         sync();
  607. # endif
  608. #endif
  609. #ifdef VMS
  610.     if (STRCMP(p_sws, "fsync") == 0)
  611.     {
  612.         if (fsync(mfp->mf_fd))
  613.         status = FAIL;
  614.     }
  615. #endif
  616. #ifdef MSDOS
  617.     if (_dos_commit(mfp->mf_fd))
  618.         status = FAIL;
  619. #else
  620. # ifdef SYNC_DUP_CLOSE
  621.     /*
  622.      * Win32 is a bit more work: Duplicate the file handle and close it.
  623.      * This should flush the file to disk.
  624.      */
  625.     if ((fd = dup(mfp->mf_fd)) >= 0)
  626.         close(fd);
  627. # endif
  628. #endif
  629. #ifdef AMIGA
  630.     /*
  631.      * Flush() only exists for AmigaDos 2.0.
  632.      * For 1.3 it should be done with close() + open(), but then the risk
  633.      * is that the open() may fail and lose the file....
  634.      */
  635. # ifdef FEAT_ARP
  636.     if (dos2)
  637. # endif
  638. # ifdef SASC
  639.     {
  640.         struct UFB *fp = chkufb(mfp->mf_fd);
  641.  
  642.         if (fp != NULL)
  643.         Flush(fp->ufbfh);
  644.     }
  645. # else
  646. #  ifdef _DCC
  647.     {
  648.         BPTR fh = (BPTR)fdtofh(mfp->mf_fd);
  649.  
  650.         if (fh != 0)
  651.         Flush(fh);
  652.         }
  653. #  else /* assume Manx */
  654.         Flush(_devtab[mfp->mf_fd].fd);
  655. #  endif
  656. # endif
  657. #endif /* AMIGA */
  658.     }
  659.  
  660.     got_int |= got_int_save;
  661.  
  662.     return status;
  663. }
  664.  
  665. /*
  666.  * insert block *hp in front of hashlist of memfile *mfp
  667.  */
  668.     static void
  669. mf_ins_hash(mfp, hp)
  670.     memfile_T    *mfp;
  671.     bhdr_T    *hp;
  672. {
  673.     bhdr_T    *hhp;
  674.     int        hash;
  675.  
  676.     hash = MEMHASH(hp->bh_bnum);
  677.     hhp = mfp->mf_hash[hash];
  678.     hp->bh_hash_next = hhp;
  679.     hp->bh_hash_prev = NULL;
  680.     if (hhp != NULL)
  681.     hhp->bh_hash_prev = hp;
  682.     mfp->mf_hash[hash] = hp;
  683. }
  684.  
  685. /*
  686.  * remove block *hp from hashlist of memfile list *mfp
  687.  */
  688.     static void
  689. mf_rem_hash(mfp, hp)
  690.     memfile_T    *mfp;
  691.     bhdr_T    *hp;
  692. {
  693.     if (hp->bh_hash_prev == NULL)
  694.     mfp->mf_hash[MEMHASH(hp->bh_bnum)] = hp->bh_hash_next;
  695.     else
  696.     hp->bh_hash_prev->bh_hash_next = hp->bh_hash_next;
  697.  
  698.     if (hp->bh_hash_next)
  699.     hp->bh_hash_next->bh_hash_prev = hp->bh_hash_prev;
  700. }
  701.  
  702. /*
  703.  * look in hash lists of memfile *mfp for block header with number 'nr'
  704.  */
  705.     static bhdr_T *
  706. mf_find_hash(mfp, nr)
  707.     memfile_T    *mfp;
  708.     blocknr_T    nr;
  709. {
  710.     bhdr_T    *hp;
  711.  
  712.     for (hp = mfp->mf_hash[MEMHASH(nr)]; hp != NULL; hp = hp->bh_hash_next)
  713.     if (hp->bh_bnum == nr)
  714.         break;
  715.     return hp;
  716. }
  717.  
  718. /*
  719.  * insert block *hp in front of used list of memfile *mfp
  720.  */
  721.     static void
  722. mf_ins_used(mfp, hp)
  723.     memfile_T    *mfp;
  724.     bhdr_T    *hp;
  725. {
  726.     hp->bh_next = mfp->mf_used_first;
  727.     mfp->mf_used_first = hp;
  728.     hp->bh_prev = NULL;
  729.     if (hp->bh_next == NULL)        /* list was empty, adjust last pointer */
  730.     mfp->mf_used_last = hp;
  731.     else
  732.     hp->bh_next->bh_prev = hp;
  733.     mfp->mf_used_count += hp->bh_page_count;
  734.     total_mem_used += hp->bh_page_count * mfp->mf_page_size;
  735. }
  736.  
  737. /*
  738.  * remove block *hp from used list of memfile *mfp
  739.  */
  740.     static void
  741. mf_rem_used(mfp, hp)
  742.     memfile_T    *mfp;
  743.     bhdr_T    *hp;
  744. {
  745.     if (hp->bh_next == NULL)        /* last block in used list */
  746.     mfp->mf_used_last = hp->bh_prev;
  747.     else
  748.     hp->bh_next->bh_prev = hp->bh_prev;
  749.     if (hp->bh_prev == NULL)        /* first block in used list */
  750.     mfp->mf_used_first = hp->bh_next;
  751.     else
  752.     hp->bh_prev->bh_next = hp->bh_next;
  753.     mfp->mf_used_count -= hp->bh_page_count;
  754.     total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
  755. }
  756.  
  757. /*
  758.  * Release the least recently used block from the used list if the number
  759.  * of used memory blocks gets to big.
  760.  *
  761.  * Return the block header to the caller, including the memory block, so
  762.  * it can be re-used. Make sure the page_count is right.
  763.  */
  764.     static bhdr_T *
  765. mf_release(mfp, page_count)
  766.     memfile_T    *mfp;
  767.     int        page_count;
  768. {
  769.     bhdr_T    *hp;
  770.     int        need_release;
  771.     buf_T    *buf;
  772.  
  773.     /* don't release while in mf_close_file() */
  774.     if (dont_release)
  775.     return NULL;
  776.  
  777.     /*
  778.      * Need to release a block if the number of blocks for this memfile is
  779.      * higher than the maximum or total memory used is over 'maxmemtot'
  780.      */
  781.     need_release = ((mfp->mf_used_count >= mfp->mf_used_count_max)
  782.                   || (total_mem_used >> 10) >= (long_u)p_mmt);
  783.  
  784.     /*
  785.      * Try to create a swap file if the amount of memory used is getting too
  786.      * high.
  787.      */
  788.     if (mfp->mf_fd < 0 && need_release && p_uc)
  789.     {
  790.     /* find for which buffer this memfile is */
  791.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  792.         if (buf->b_ml.ml_mfp == mfp)
  793.         break;
  794.     if (buf != NULL && buf->b_may_swap)
  795.         ml_open_file(buf);
  796.     }
  797.  
  798.     /*
  799.      * don't release a block if
  800.      *    there is no file for this memfile
  801.      * or
  802.      *    the number of blocks for this memfile is lower than the maximum
  803.      *      and
  804.      *    total memory used is not up to 'maxmemtot'
  805.      */
  806.     if (mfp->mf_fd < 0 || !need_release)
  807.     return NULL;
  808.  
  809.     for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
  810.     if (!(hp->bh_flags & BH_LOCKED))
  811.         break;
  812.     if (hp == NULL)    /* not a single one that can be released */
  813.     return NULL;
  814.  
  815.     /*
  816.      * If the block is dirty, write it.
  817.      * If the write fails we don't free it.
  818.      */
  819.     if ((hp->bh_flags & BH_DIRTY) && mf_write(mfp, hp) == FAIL)
  820.     return NULL;
  821.  
  822.     mf_rem_used(mfp, hp);
  823.     mf_rem_hash(mfp, hp);
  824.  
  825.     /*
  826.      * If a bhdr_T is returned, make sure that the page_count of bh_data is
  827.      * right
  828.      */
  829.     if (hp->bh_page_count != page_count)
  830.     {
  831.     vim_free(hp->bh_data);
  832.     if ((hp->bh_data = alloc(mfp->mf_page_size * page_count)) == NULL)
  833.     {
  834.         vim_free(hp);
  835.         return NULL;
  836.     }
  837.     hp->bh_page_count = page_count;
  838.     }
  839.     return hp;
  840. }
  841.  
  842. /*
  843.  * release as many blocks as possible
  844.  * Used in case of out of memory
  845.  *
  846.  * return TRUE if any memory was released
  847.  */
  848.     int
  849. mf_release_all()
  850. {
  851.     buf_T    *buf;
  852.     memfile_T    *mfp;
  853.     bhdr_T    *hp;
  854.     int        retval = FALSE;
  855.  
  856.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  857.     {
  858.     mfp = buf->b_ml.ml_mfp;
  859.     if (mfp != NULL)
  860.     {
  861.         /* If no swap file yet, may open one */
  862.         if (mfp->mf_fd < 0 && buf->b_may_swap)
  863.         ml_open_file(buf);
  864.  
  865.         /* only if there is a swapfile */
  866.         if (mfp->mf_fd >= 0)
  867.         {
  868.         for (hp = mfp->mf_used_last; hp != NULL; )
  869.         {
  870.             if (!(hp->bh_flags & BH_LOCKED)
  871.                 && (!(hp->bh_flags & BH_DIRTY)
  872.                 || mf_write(mfp, hp) != FAIL))
  873.             {
  874.             mf_rem_used(mfp, hp);
  875.             mf_rem_hash(mfp, hp);
  876.             mf_free_bhdr(hp);
  877.             hp = mfp->mf_used_last;    /* re-start, list was changed */
  878.             retval = TRUE;
  879.             }
  880.             else
  881.             hp = hp->bh_prev;
  882.         }
  883.         }
  884.     }
  885.     }
  886.     return retval;
  887. }
  888.  
  889. /*
  890.  * Allocate a block header and a block of memory for it
  891.  */
  892.     static bhdr_T *
  893. mf_alloc_bhdr(mfp, page_count)
  894.     memfile_T    *mfp;
  895.     int        page_count;
  896. {
  897.     bhdr_T    *hp;
  898.  
  899.     if ((hp = (bhdr_T *)alloc((unsigned)sizeof(bhdr_T))) != NULL)
  900.     {
  901.     if ((hp->bh_data = (char_u *)alloc(mfp->mf_page_size * page_count))
  902.                                       == NULL)
  903.     {
  904.         vim_free(hp);        /* not enough memory */
  905.         return NULL;
  906.     }
  907.     hp->bh_page_count = page_count;
  908.     }
  909.     return hp;
  910. }
  911.  
  912. /*
  913.  * Free a block header and the block of memory for it
  914.  */
  915.     static void
  916. mf_free_bhdr(hp)
  917.     bhdr_T    *hp;
  918. {
  919.     vim_free(hp->bh_data);
  920.     vim_free(hp);
  921. }
  922.  
  923. /*
  924.  * insert entry *hp in the free list
  925.  */
  926.     static void
  927. mf_ins_free(mfp, hp)
  928.     memfile_T    *mfp;
  929.     bhdr_T    *hp;
  930. {
  931.     hp->bh_next = mfp->mf_free_first;
  932.     mfp->mf_free_first = hp;
  933. }
  934.  
  935. /*
  936.  * remove the first entry from the free list and return a pointer to it
  937.  * Note: caller must check that mfp->mf_free_first is not NULL!
  938.  */
  939.     static bhdr_T *
  940. mf_rem_free(mfp)
  941.     memfile_T    *mfp;
  942. {
  943.     bhdr_T    *hp;
  944.  
  945.     hp = mfp->mf_free_first;
  946.     mfp->mf_free_first = hp->bh_next;
  947.     return hp;
  948. }
  949.  
  950. /*
  951.  * read a block from disk
  952.  *
  953.  * Return FAIL for failure, OK otherwise
  954.  */
  955.     static int
  956. mf_read(mfp, hp)
  957.     memfile_T    *mfp;
  958.     bhdr_T    *hp;
  959. {
  960.     off_t    offset;
  961.     unsigned    page_size;
  962.     unsigned    size;
  963.  
  964.     if (mfp->mf_fd < 0)        /* there is no file, can't read */
  965.     return FAIL;
  966.  
  967.     page_size = mfp->mf_page_size;
  968.     offset = (off_t)page_size * hp->bh_bnum;
  969.     size = page_size * hp->bh_page_count;
  970.     if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
  971.     {
  972.     EMSG(_("E294: Seek error in swap file read"));
  973.     return FAIL;
  974.     }
  975.     if ((unsigned)vim_read(mfp->mf_fd, hp->bh_data, size) != size)
  976.     {
  977.     EMSG(_("E295: Read error in swap file"));
  978.     return FAIL;
  979.     }
  980.     return OK;
  981. }
  982.  
  983. /*
  984.  * write a block to disk
  985.  *
  986.  * Return FAIL for failure, OK otherwise
  987.  */
  988.     static int
  989. mf_write(mfp, hp)
  990.     memfile_T    *mfp;
  991.     bhdr_T    *hp;
  992. {
  993.     off_t    offset;        /* offset in the file */
  994.     blocknr_T    nr;        /* block nr which is being written */
  995.     bhdr_T    *hp2;
  996.     unsigned    page_size;  /* number of bytes in a page */
  997.     unsigned    page_count; /* number of pages written */
  998.     unsigned    size;        /* number of bytes written */
  999.  
  1000.     if (mfp->mf_fd < 0)        /* there is no file, can't write */
  1001.     return FAIL;
  1002.  
  1003.     if (hp->bh_bnum < 0)    /* must assign file block number */
  1004.     if (mf_trans_add(mfp, hp) == FAIL)
  1005.         return FAIL;
  1006.  
  1007.     page_size = mfp->mf_page_size;
  1008.  
  1009.     /*
  1010.      * We don't want gaps in the file. Write the blocks in front of *hp
  1011.      * to extend the file.
  1012.      * If block 'mf_infile_count' is not in the hash list, it has been
  1013.      * freed. Fill the space in the file with data from the current block.
  1014.      */
  1015.     for (;;)
  1016.     {
  1017.     nr = hp->bh_bnum;
  1018.     if (nr > mfp->mf_infile_count)        /* beyond end of file */
  1019.     {
  1020.         nr = mfp->mf_infile_count;
  1021.         hp2 = mf_find_hash(mfp, nr);    /* NULL catched below */
  1022.     }
  1023.     else
  1024.         hp2 = hp;
  1025.  
  1026.     offset = (off_t)page_size * nr;
  1027.     if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
  1028.     {
  1029.         EMSG(_("E296: Seek error in swap file write"));
  1030.         return FAIL;
  1031.     }
  1032.     if (hp2 == NULL)        /* freed block, fill with dummy data */
  1033.         page_count = 1;
  1034.     else
  1035.         page_count = hp2->bh_page_count;
  1036.     size = page_size * page_count;
  1037.     if ((unsigned)vim_write(mfp->mf_fd,
  1038.          (hp2 == NULL ? hp : hp2)->bh_data, size) != size)
  1039.     {
  1040.         /*
  1041.          * Avoid repeating the error message, this mostly happens when the
  1042.          * disk is full. We give the message again only after a succesful
  1043.          * write or when hitting a key. We keep on trying, in case some
  1044.          * space becomes available.
  1045.          */
  1046.         if (!did_swapwrite_msg)
  1047.         EMSG(_("E297: Write error in swap file"));
  1048.         did_swapwrite_msg = TRUE;
  1049.         return FAIL;
  1050.     }
  1051.     did_swapwrite_msg = FALSE;
  1052.     if (hp2 != NULL)            /* written a non-dummy block */
  1053.         hp2->bh_flags &= ~BH_DIRTY;
  1054.                         /* appended to the file */
  1055.     if (nr + (blocknr_T)page_count > mfp->mf_infile_count)
  1056.         mfp->mf_infile_count = nr + page_count;
  1057.     if (nr == hp->bh_bnum)            /* written the desired block */
  1058.         break;
  1059.     }
  1060.     return OK;
  1061. }
  1062.  
  1063. /*
  1064.  * Make block number for *hp positive and add it to the translation list
  1065.  *
  1066.  * Return FAIL for failure, OK otherwise
  1067.  */
  1068.     static int
  1069. mf_trans_add(mfp, hp)
  1070.     memfile_T    *mfp;
  1071.     bhdr_T    *hp;
  1072. {
  1073.     bhdr_T    *freep;
  1074.     blocknr_T    new_bnum;
  1075.     int        hash;
  1076.     NR_TRANS    *np;
  1077.     int        page_count;
  1078.  
  1079.     if (hp->bh_bnum >= 0)            /* it's already positive */
  1080.     return OK;
  1081.  
  1082.     if ((np = (NR_TRANS *)alloc((unsigned)sizeof(NR_TRANS))) == NULL)
  1083.     return FAIL;
  1084.  
  1085. /*
  1086.  * get a new number for the block.
  1087.  * If the first item in the free list has sufficient pages, use its number
  1088.  * Otherwise use mf_blocknr_max.
  1089.  */
  1090.     freep = mfp->mf_free_first;
  1091.     page_count = hp->bh_page_count;
  1092.     if (freep != NULL && freep->bh_page_count >= page_count)
  1093.     {
  1094.     new_bnum = freep->bh_bnum;
  1095.     /*
  1096.      * If the page count of the free block was larger, recude it.
  1097.      * If the page count matches, remove the block from the free list
  1098.      */
  1099.     if (freep->bh_page_count > page_count)
  1100.     {
  1101.         freep->bh_bnum += page_count;
  1102.         freep->bh_page_count -= page_count;
  1103.     }
  1104.     else
  1105.     {
  1106.         freep = mf_rem_free(mfp);
  1107.         vim_free(freep);
  1108.     }
  1109.     }
  1110.     else
  1111.     {
  1112.     new_bnum = mfp->mf_blocknr_max;
  1113.     mfp->mf_blocknr_max += page_count;
  1114.     }
  1115.  
  1116.     np->nt_old_bnum = hp->bh_bnum;        /* adjust number */
  1117.     np->nt_new_bnum = new_bnum;
  1118.  
  1119.     mf_rem_hash(mfp, hp);            /* remove from old hash list */
  1120.     hp->bh_bnum = new_bnum;
  1121.     mf_ins_hash(mfp, hp);            /* insert in new hash list */
  1122.  
  1123.     hash = MEMHASH(np->nt_old_bnum);        /* insert in trans list */
  1124.     np->nt_next = mfp->mf_trans[hash];
  1125.     mfp->mf_trans[hash] = np;
  1126.     if (np->nt_next != NULL)
  1127.     np->nt_next->nt_prev = np;
  1128.     np->nt_prev = NULL;
  1129.  
  1130.     return OK;
  1131. }
  1132.  
  1133. /*
  1134.  * Lookup a tranlation from the trans lists and delete the entry
  1135.  *
  1136.  * Return the positive new number when found, the old number when not found
  1137.  */
  1138.     blocknr_T
  1139. mf_trans_del(mfp, old_nr)
  1140.     memfile_T    *mfp;
  1141.     blocknr_T    old_nr;
  1142. {
  1143.     int        hash;
  1144.     NR_TRANS    *np;
  1145.     blocknr_T    new_bnum;
  1146.  
  1147.     hash = MEMHASH(old_nr);
  1148.     for (np = mfp->mf_trans[hash]; np != NULL; np = np->nt_next)
  1149.     if (np->nt_old_bnum == old_nr)
  1150.         break;
  1151.     if (np == NULL)        /* not found */
  1152.     return old_nr;
  1153.  
  1154.     mfp->mf_neg_count--;
  1155.     new_bnum = np->nt_new_bnum;
  1156.     if (np->nt_prev != NULL)        /* remove entry from the trans list */
  1157.     np->nt_prev->nt_next = np->nt_next;
  1158.     else
  1159.     mfp->mf_trans[hash] = np->nt_next;
  1160.     if (np->nt_next != NULL)
  1161.     np->nt_next->nt_prev = np->nt_prev;
  1162.     vim_free(np);
  1163.  
  1164.     return new_bnum;
  1165. }
  1166.  
  1167. /*
  1168.  * Set mfp->mf_ffname according to mfp->mf_fname and some other things.
  1169.  * Only called when creating or renaming the swapfile.    Either way it's a new
  1170.  * name so we must work out the full path name.
  1171.  */
  1172.     void
  1173. mf_set_ffname(mfp)
  1174.     memfile_T    *mfp;
  1175. {
  1176.     mfp->mf_ffname = FullName_save(mfp->mf_fname, FALSE);
  1177. }
  1178.  
  1179. /*
  1180.  * Make the name of the file used for the memfile a full path.
  1181.  * Used before doing a :cd
  1182.  */
  1183.     void
  1184. mf_fullname(mfp)
  1185.     memfile_T    *mfp;
  1186. {
  1187.     if (mfp != NULL && mfp->mf_fname != NULL && mfp->mf_ffname != NULL)
  1188.     {
  1189.     vim_free(mfp->mf_fname);
  1190.     mfp->mf_fname = mfp->mf_ffname;
  1191.     mfp->mf_ffname = NULL;
  1192.     }
  1193. }
  1194.  
  1195. /*
  1196.  * return TRUE if there are any translations pending for 'mfp'
  1197.  */
  1198.     int
  1199. mf_need_trans(mfp)
  1200.     memfile_T    *mfp;
  1201. {
  1202.     return (mfp->mf_fname != NULL && mfp->mf_neg_count > 0);
  1203. }
  1204.  
  1205. /*
  1206.  * Open a swap file for a memfile.
  1207.  * The "fname" must be in allocated memory, and is consumed (also when an
  1208.  * error occurs).
  1209.  */
  1210.     static void
  1211. mf_do_open(mfp, fname, flags)
  1212.     memfile_T    *mfp;
  1213.     char_u    *fname;
  1214.     int        flags;        /* flags for open() */
  1215. {
  1216. #ifdef HAVE_LSTAT
  1217.     struct stat sb;
  1218. #endif
  1219.  
  1220.     mfp->mf_fname = fname;
  1221.  
  1222.     /*
  1223.      * Get the full path name before the open, because this is
  1224.      * not possible after the open on the Amiga.
  1225.      * fname cannot be NameBuff, because it must have been allocated.
  1226.      */
  1227.     mf_set_ffname(mfp);
  1228. #if defined(MSDOS) || defined(MSWIN) || defined(RISCOS)
  1229.     /*
  1230.      * A ":!cd e:xxx" may change the directory without us knowning, use the
  1231.      * full pathname always.  Careful: This frees fname!
  1232.      */
  1233.     mf_fullname(mfp);
  1234. #endif
  1235.  
  1236. #ifdef HAVE_LSTAT
  1237.     /*
  1238.      * Extra security check: When creating a swap file it really shouldn't
  1239.      * exist yet.  If there is a symbolic link, this is most likely an attack.
  1240.      */
  1241.     if ((flags & O_CREAT) && mch_lstat((char *)mfp->mf_fname, &sb) >= 0)
  1242.     {
  1243.     mfp->mf_fd = -1;
  1244.     EMSG(_("E300: Swap file already exists (symlink attack?)"));
  1245.     }
  1246.     else
  1247. #endif
  1248.  
  1249.     /*
  1250.      * try to open the file
  1251.      */
  1252.     mfp->mf_fd = open(
  1253. #ifdef VMS
  1254.         vms_fixfilename(mfp->mf_fname),
  1255. #else
  1256.         (char *)mfp->mf_fname,
  1257. #endif
  1258.         flags | O_EXTRA
  1259. #if defined(UNIX) || defined(RISCOS) || defined(VMS)
  1260.             , (mode_t)0600        /* open in rw------- mode */
  1261. #endif
  1262. #if defined(MSDOS) || defined(MSWIN) || defined(__EMX__)
  1263.             , S_IREAD | S_IWRITE    /* open read/write */
  1264. #endif
  1265.             );
  1266.  
  1267.     /*
  1268.      * If the file cannot be opened, use memory only
  1269.      */
  1270.     if (mfp->mf_fd < 0)
  1271.     {
  1272.     vim_free(mfp->mf_fname);
  1273.     vim_free(mfp->mf_ffname);
  1274.     mfp->mf_fname = NULL;
  1275.     mfp->mf_ffname = NULL;
  1276.     }
  1277.     else
  1278.     mch_hide(mfp->mf_fname);    /* try setting the 'hidden' flag */
  1279. }
  1280.